﻿// Inner Fire 游戏引擎库
// Humanoid - 通用骨架动画
//
// Copyright (c) 2025 by 尔西大帝. All rights reserved.
//
// 所属层级：应用层(4)
// 用于Humanoid动画的计算
//
// Author: 尔西大帝
// Email: 2670613871@qq.com
// Created: 2025-05-17

#pragma once

#include <DirectXMath.h>
#include <EASTL/vector.h>
#include <game/animation/armature_node.h>
#include <game/animation/avatar_id.h>
#include <graphics/transform_def.h>
#include <game/animation/snapshot.h>

namespace ifire::game {
class Animator;
class Avatar;
class Armature;
class AnimationClip;

class Humanoid {
public:
  Humanoid(Animator* animator);
  Humanoid(const Humanoid& lhs) = delete;
  Humanoid& operator=(const Humanoid& lhs) = delete;
  ~Humanoid() = default;

  // 以一个动画的Avatar，计算动画的项目
  void CalcAnimeFrame(Snapshot& desc);

  // 是否对脚部的IK进行修正
  inline void UseFootFix(bool enable) { use_foot_fix_ = enable; }
  // 是否在最后对骨骼角度进行修正
  inline void UseDirectionFix(bool enable) { use_direction_fix_ = enable; }
  // 是否使用缩放对动画进行修正
  inline void UseScaleFfix(bool enable) { use_scale_fix_ = enable; }
  // 是否使用RootMotion
  inline void UseRootMotion(bool enable) { use_root_motion_ = enable; }
  // 是否对骨骼的长度进行修正
  inline void UseLengthFix(bool enable) { use_length_fix_ = enable; }

private:
  IMat CalcNewTransform(ArmatureNode* node, ArmatureNode* b_node);
  // 计算动画
  void CalcAnimation(Snapshot& desc);
  // 印射骨骼
  void MapSkeleton(MatrixList& bones);
  // 修复骨骼的方向
  void FixDirection(MatrixList& bones);
  // 修复Foot的位置
  void FixFoot(MatrixList& bones);
  // 保存Foot的项目
  void SaveFootPosition(int avatar_id, FVec a, FVec b);

  Animator* animator_;
  const Armature* armature_;
  const Avatar* avatar_;

  // 动画的Avatar
  const Avatar* anime_avatar_;
  const ArmatureTree* anime_tree_;

  // 用于保存每一种项目的计算结果。
  MatrixList transforms_;
  // 用于B级的父级，这个是和Anime的骨骼对应的。A的在Animator中。
  MatrixList b_parents_;

  // 用于保存Foot的位置
  float a_foot_min, b_foot_min;
  float a_height, b_height;

  // 用于保存临时变换，避免每次的传递
  IMat a_parent, b_parent, a_global, b_global;

  // 用于对动画进行缩放
  IVec scale_vec_;

  // 用于保存动画与Frame，以便不在所有的层级中传递
  AnimationClip* clip_;
  // 用于保存动画与Frame，以便不在所有的层级中传递
  float frame_;

  // 是否对脚部的IK进行修正
  bool use_foot_fix_;
  // 是否在最后对骨骼角度进行修正
  bool use_direction_fix_;
  // 是否使用缩放对动画进行修正
  bool use_scale_fix_;
  // 是否使用RootMotion
  bool use_root_motion_;
  // 是否对骨骼的长度进行修正
  // TIPS：如果开启这个东西，会导致有些腾空的动作出现问题。
  // 我的猜测是腾空动画是通过修改Hips来实现，而RootMotion还在原地。
  // 但这是处理很多异性骨骼时效果很好（比如有一个动画，他手特别长），这样不会造成模型拉伸。
  bool use_length_fix_;
};

} // namespace ifire::game